package cmp.compile;

/******************************************************
 * All methods used the class to load groups from file
 * TODO: the Groups table will have all summed counts (done but broken)
 */
import java.io.*;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.util.Vector;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cmp.compile.CompileMain;
import assem.DBConn;
import cmp.database.DBinfo;
import cmp.main.Globals;
import cmp.compile.panels.CompilePanel;
import util.Debug.ErrorReport;

public class MethodUserDef {	

	// bunch of heuristic to figure out non-informative names
	// copied from jpave.DoUniProt
	private boolean goodDescript (String des) {
		des = des.toLowerCase();
		if (des.contains("uncharacterized protein") || 
	    		des.contains("putative uncharacterized") || 
	    		des.contains("hypothetical_protein") || 
	    		des.contains("expressed protein") || 
	    		des.contains("predicted protein") ||
	    		des.contains("whole genome shotgun") ||
	    		des.equals("orf"))
	    	{
	    	        return false;
	    	}
		String [] words = des.split(" ");
		if (words.length > 2) return true;

		// many are just a name or name protein or name (fragment)
		boolean name = false;
		int let=0, num=0;
		for (int i=0; i < words[0].length(); i++) {
			char c = words[0].charAt(i);
			if (Character.isDigit(c)) num++;
			else if (Character.isLetter(c)) let++;
		}
		int wl = words[0].length();
		double x = (num > 0) ? ((double) wl/ (double) num) : 0;
		if (num > 3 || (wl <= 5 && x > 1)) name = true;
		
		if (words.length == 1 && name) return false;
		if (name &&  des.endsWith("protein")) return false;
		if (name &&  des.endsWith("(fragment)")) return false;
		return true;
	}
	/***********************************************************
	 * Called by CompileMain to add a file of orthologs
	 */
	 public boolean run(int idx, DBConn dbc, CompilePanel panel) {
		String [] settings = panel.getMethodSettings(idx).split(":");	
		groupFile = settings[1];
		cmpPanel = panel;
		mDB = dbc;	
		prefix = panel.getMethodPrefix(idx);
		
		if (!processGroupFile(idx)) return false;

		CompileMain.PrtSpMsg(1, "");
		return true;
	}
		
	/*****************************************************************
	 * Called by all methods to load the file just generated
	 */
	 public boolean run(int idx, String file, DBConn dbc, CompilePanel panel) {	
		groupFile = file;
		cmpPanel = panel;
		mDB = dbc;	
		prefix = panel.getMethodPrefix(idx);
			
		if (!processGroupFile(idx)) return false;
	
		return true;
	}
	 /***************************************************
	  * loadGroupFile
	  */
	 private boolean processGroupFile(int idx) {
		long startTime = CompileMain.getTime();
		String comment = cmpPanel.getMethodComment(idx);
		String methodName = cmpPanel.getMethodNameAt(idx);
		String methodType = cmpPanel.getMethodTypeAt(idx);
	 
		CompileMain.PrtSpMsg(1, "");
		CompileMain.PrtSpMsg(0, "Start load of " + methodName + " (" + methodType + ") groups from file " + groupFile);		
		CompileMain.PrtSpMsg(1, "Prefix:     " + prefix);
		if (!comment.equals("")) CompileMain.PrtSpMsg(1, "Remark:    " + comment);
		CompileMain.PrtSpMsg(1, "Group file: " + groupFile);
							
		File f = new File(groupFile);
		if (!f.exists()) {
			groupFile = cmpPanel.getCurrentProjectDirectory() + "/" + groupFile;
			f = new File (groupFile);
			if (!f.exists()) {
				CompileMain.PrtError("Cannot find group file " + f.getAbsolutePath());
				System.err.println("If adding OrthoMCL, run Add New Clusters again -- ");
				System.err.println("  for some reason if sometimes fails the first time but works the second");
				return false;
			}
		}

		// LOAD METHOD, GROUPS and MEMBERS
		if (!step1_loadMethod(methodName, methodType, prefix, comment)) return false;
		if (!step2_initDSfromDB()) return false;
		if (!step3_readFileofClusters()) return false;
		step4_updateClusterCnts(PMid);
		step5_updateGroupGOs(PMid);
		
		CompileMain.PrtSpMsgTime(0, "\nFinish load of " + methodName + " groups", startTime);
		return true;
	 }
	 /**************************************************************
	  * load method into pog_method table of database
	  */
	 private boolean step1_loadMethod(String name, String method, String prefix, String descript) {		
	 try {
		if (prefix.length() > 3) {
			System.err.println("Prefix is too long: " + prefix);
			return false;
		}

		if (descript.contains("'")) {
			descript.replace("'", "");
			CompileMain.PrtWarn("Removed quotes from description string: " + descript);
		}
		
		PreparedStatement ps = mDB.prepareStatement("INSERT INTO pog_method (PMstr, PMtype, prefix, adddate, description) " +
				" values(?,?,?,NOW(),?)");
		ps.setString(1, name);
		ps.setString(2, method);
		ps.setString(3, prefix);
		ps.setString(4, descript);
		ps.execute();
/*		mDB.executeUpdate("INSERT INTO pog_method (PMstr, PMtype, prefix, adddate, description) " +
			"values (" + quote(name) + "," + quote(method) + "," + 
				quote(prefix) + "," + " Current_Timestamp, " + quote(descript) + ");");	*/
		
		ResultSet rs = mDB.executeQuery( "select last_insert_id() as PMid");
		if (rs.next()) 
			PMid = rs.getInt("PMid");
		else 
			ErrorReport.die("error getting last PMid");
		rs.close();

		// once pog_method is added, everything can be removed if error
		if (!mDB.tableHasColumn("unitrans", prefix))
			mDB.executeUpdate("ALTER TABLE unitrans ADD " + prefix + " VARCHAR(30)");
		return true;
		
	} catch (Exception e) {ErrorReport.die(e, "error getting last PMid");return false;}
	}
	 /***************************************************
	  * initialize: utMap, prefMap, specVec from database
	  */
	 private boolean step2_initDSfromDB() {
	 try {
		ResultSet rs;
		String line;
		File file = new File(groupFile);
		if (!file.exists()) {
			file = new File(cmpPanel.getCurrentProjectDirectory() + "/" + groupFile);
			if (!file.exists()) {
				CompileMain.PrtError("File does not exist:" + groupFile);
				return false;
			}
		}
			
		/**** Get prefixes from group file and database *********
		 * need to make sure the ASMid is correct **************/
		nAsm = mDB.executeCount("SELECT COUNT(*) FROM assembly");

		HashMap <Integer, String> asmMap = new HashMap <Integer, String> ();
		
		rs = mDB.executeQuery("SELECT ASMid, ASMstr FROM assembly");
		while (rs.next()) asmMap.put(rs.getInt(1), rs.getString(2));
		
		BufferedReader reader = new BufferedReader ( new FileReader ( file ) );
		int nFound=0;
		while ((line = reader.readLine()) != null) 
		{
			if ( line.length() == 0 || line.charAt(0) == '#' ) continue;  			
			String[] members = line.split(" ");
			if (members == null || members.length < 2) continue;
			
			for (int i=1; i< members.length; i++) { // first is group - ignore
				Matcher m = grpPat.matcher(members[i]);
				if (!m.find()) continue;
				
				String preStr = m.group(1);  				
				if (prefMap.containsKey(preStr)) continue;
				
				String seqID = m.group(2);
				rs = mDB.executeQuery("SELECT ASMid FROM unitrans WHERE UTstr='" + seqID + "'");
				if (!rs.next()) CompileMain.die("No sequence ID in database of " + seqID);
				prefMap.put(preStr, rs.getInt(1));
   				nFound++;
			}
			if (nFound >= nAsm) break;
		}
		reader.close();
		CompileMain.PrtSpMsg(2, "Prefixes in group file correspond to datasets: ");
		String msg = String.format("%10s  %10s", "DataSet", "Prefix");
		CompileMain.PrtSpMsg(3, msg);
		
		for (String pfx : prefMap.keySet()) {
			int idx = prefMap.get(pfx);
			msg = String.format("%10s  %10s", asmMap.get(idx), pfx);
			CompileMain.PrtSpMsg(3, msg);
		}
		
		/*** Get Unitrans Strings and IDs from database ****/
		rs = mDB.executeQuery("SELECT UTid, UTstr FROM unitrans");
		while (rs.next()) {
			utMap.put(rs.getString("UTstr"), rs.getInt("UTid"));
		}
		rs.close();
		
		/** get species name (i.e. PAVE assemblyID) from interface for Species count string***/
		for (int i=0; i < cmpPanel.getAssemblyCount(); i++) {
			specVec.add(cmpPanel.getAssemblyName(i));
		}
		 return true;
	 }
	 catch (Exception e) {ErrorReport.reportError(e, "initialize data structures"); return false; }
	 }
	 
	/************************************************************
	* load the groups into pog_groups and group_members
	* orthoMCL format; the prefix of names are ASMstr, example input:
	* D3: dm1|cari_01 dm2|demo_mix_01
	*************************************************************/
	private boolean step3_readFileofClusters() {
	try {		
		String line;
		int group=0, skip=0, add=0, badPre=0;
		long ts = CompileMain.getTime();
		
		File file = new File(groupFile);
		BufferedReader reader = new BufferedReader ( new FileReader ( file ) );
		String POGsql = step3a_createPOGsql(specVec);	
		
		while ((line = reader.readLine()) != null) 
		{
			if ( line.length() == 0 || line.charAt(0) == '#' ) continue;  			
			String [] members = line.split(" ");
			if (members == null || members.length < 2) {
				System.err.println("Bad line: " + line);
				continue;
			}
			if (members.length==2) continue;

			group++;
			if (group > 999999) 
				ErrorReport.die("More than 999999 groups - email tcw@agcol.arizona.edu");
			String PGstr = String.format("%s_%06d", prefix, group);    			
    		
    	/** compute # of members per assembly to be loaded with assembly information **/				
			int cntMem=0;
			int ASMcnt [] = new int [nAsm+1]; // count how many from each assm	
			for (int i=0; i<= nAsm; i++) ASMcnt[i] = 0;
			
			for (int i=1; i< members.length; i++) { // first is group - ignore
				Matcher m = grpPat.matcher(members[i]);
				if (m.find()) {
					String preStr = m.group(1);
					if (prefMap.containsKey(preStr)) {
						int j = prefMap.get(preStr);
						ASMcnt[j]++;
						cntMem++;
    				}
				else {
					CompileMain.PrtWarn("Invalid prefix: " + preStr);
					badPre++;
					if (badPre>10)  {	
						CompileMain.PrtWarn("Example Line :" + line);
						CompileMain.die("Too many bad prefixes -- check file");
					}
					continue;
				}
    			}
    		}
			
	    	/** add group to database -- need PGid for adding members **/
			int PGid = step3b_loadGroup(POGsql, PGstr, PMid, cntMem, ASMcnt);
			ASMcnt = null;
               
    	/** find members and add to database **/ 
			if (group % 100 == 0)
				System.err.print("      Adding group #" + group + " members " + members.length + "\r"); 
			add=skip=0;
			Vector <Integer> UTidVec = new Vector <Integer> ();
			for (int i=1; i< members.length; i++) {
				String SEQstr = "";  				
				Matcher m = grpPat.matcher(members[i]);
				if (m.find()) SEQstr = m.group(2);
				else  CompileMain.die("Invalid line: " + line + " member: " + members[i]);
				
				int SEQid=0;
			    	if (utMap.containsKey(SEQstr)) SEQid = utMap.get(SEQstr); 
			    	else {
			    		if (skip < 5)
			    			CompileMain.PrtWarn("File contains sequence identifer not in database '" 
									+ SEQstr + "'");
						else if (skip==10) 
							CompileMain.PrtWarn("Surpressing further such error messages");
						skip++;
						if (skip>100 && add==0) 
							CompileMain.die("Too many bad indentifiers and no good ones -- check file");
						continue;
			    	}
		    		
				step3c_loadMember(PGid, PGstr, SEQstr, SEQid);	
				UTidVec.add(utMap.get(SEQstr));
				add++;
			}
    			
    	/** add entry to pog_hits and compute best hit **/
			step3d_addBestHits(PGid, UTidVec); 
			UTidVec.clear();
		} // end while reading groups
			
		CompileMain.PrtSpMsg(2, "Total groups: " + group + "  with annoDB hits: " + cntHits);
		CompileMain.PrtSpMsgTime(2, "Sequences in groups: " + cntSeqs, ts);
		CompileMain.PrtSpMsg(2,"");
		return true;
	}
	catch (Exception e) {ErrorReport.prtReport(e, "loading POGS");return false;}
	}
	/* Create string for adding groups, along with assembly columns that have names "A__<assmid>" */
	private String step3a_createPOGsql(Vector <String> specVec) {
	try {
		String POGsql=null;
   		ResultSet rs = mDB.executeQuery("show columns from pog_groups like 'A\\_\\_%'"); //Mysql ignores _ here if not escaped
		while (rs.next())
		{
			String colName = rs.getString(1);
			String[] tokens = colName.split("__");

    		if (tokens == null || tokens.length < 2) 
    				ErrorReport.die("createStrPOG parsing " + colName);
		}
		rs.close();
		
		POGsql = "INSERT INTO pog_groups (PGstr, PMid, count ";
		
		// same as received in columns, so output should be the same order
		for (int i=0; i < specVec.size(); i++) {
			POGsql += ", A__" + specVec.get(i);
		}
		
		POGsql += ", taxa) values (";
		return POGsql;
	}
	catch (Exception e) {ErrorReport.die(e, "createStrPOG"); return null;}
	}
	
	/* load group into database 12/16/14 -- add printing strQ on error */
	private int step3b_loadGroup(String POGsql, String PGstr, int PMid, int count, int [] ASMcnt) {
		String strQ = POGsql + quote(PGstr) + "," + PMid + "," + count + ",";
		try {
			// computing taxa 
			int nASM=0, nGT1=0, id=0;
			for (int i=1; i<ASMcnt.length; i++) {
				strQ += ASMcnt[i] + ",";
				if (ASMcnt[i]>0) nASM++;
				if (ASMcnt[i]>1) nGT1++;
			}
			String taxo = nASM + "x1";
			if (nGT1>0) taxo = nASM + "xN";
			
			strQ +=  "'" + taxo + "');";
			mDB.executeUpdate(strQ);
				
			strQ = "select last_insert_id() as PGid";
			ResultSet rs = mDB.executeQuery( strQ );
			if (rs.next()) id = rs.getInt("PGid");
			else ErrorReport.die("error getting last PGid");
			rs.close();
			return id;
		} catch (Exception e) {ErrorReport.die(e, "loading group " + PGstr + "\nSQL=" + strQ); return 0;}
	}

	/* load member from group */
	private void step3c_loadMember(int PGid, String PGstr, String MEMstr, int UTid) {
	    try {    		
	    		mDB.executeUpdate("INSERT INTO pog_members (PGid, PGstr, UTid, UTstr) values (" +
	    			PGid 			+ "," +
	    			quote(PGstr) 	+ "," +
	    			UTid			+ "," +
	    			quote(MEMstr)	+ ");"
	    			);
			mDB.executeUpdate("UPDATE unitrans SET " + prefix + " = '" + PGstr + "'" + 
					" WHERE UTstr = '" + MEMstr + "'");
			cntSeqs++;
		} catch (Exception e) {ErrorReport.die(e, "error entering member");}   
	}
	
	/** Add best hit for this group 
	 * Description can be the same with many different IDs
	 * So find common description and use that for percentage
	 * And find a representative id
	 * */
	private void step3d_addBestHits(int PGid, Vector <Integer> UTidVec) {	
		try {
			int grpSize= UTidVec.size();
			
			// build search string for pog members from this database
			String utList=null;
			for (int i=0; i < grpSize; i++) {
				int UTid = UTidVec.get(i);
				if (utList==null) utList = " (UTid = " + UTid;
				else utList += " or UTid = " + UTid;		
			}
			utList += ")";
			
			ResultSet rs = mDB.executeQuery(
					"SELECT unitrans_hits.UTid, unitrans_hits.HITid, unitrans_hits.HITstr, unitrans_hits.e_value, " +
					"unitrans_hits.bestAnno, unique_hits.description " +
					"FROM unitrans_hits " +
					"JOIN unique_hits " +
					"WHERE " + utList + " AND unitrans_hits.HITid = unique_hits.HITid");

			HashMap <String, Hits> 	desHits = new HashMap <String, Hits> ();
			
			int count=0;
			while (rs.next()) {	
				int UTid = rs.getInt(1);
				int HITid = rs.getInt(2);
				if (HITid == 0) continue; // seq may not have any hits
							
				String HITstr = rs.getString(3);
				double eval = rs.getDouble(4);
				int bestAnno = rs.getInt(5); // 0 or 1
				String descript = rs.getString(6);
	
				if (!desHits.containsKey(descript)) {
					Hits x = new Hits(UTid, HITid, HITstr, descript, bestAnno, eval, goodDescript(descript));
					desHits.put(descript, x);			
				}
				else {
					Hits x = desHits.get(descript);
					x.add(UTid, HITid, HITstr, bestAnno, eval);
				}
				count++;
			}
			rs.close();
			if (count==0) return;
					
			// find the best
			int bestid = 0, bestcnt=0, bestban=0;
			String beststr = null, descript="";
			Double besteval = 100.0;
			boolean bestgood=false;
			
			for (String des : desHits.keySet() ) {
				Hits hit = desHits.get(des);
				boolean isBest=false;
				
				if (hit.good && !bestgood) isBest=true;
				else if (hit.good == bestgood) {
					if (hit.cnt > bestcnt) isBest=true;
					else if (hit.cnt == bestcnt) {
						if (hit.ban > bestban) isBest=true;
						else if (hit.ban==bestban  && hit.eval < besteval) isBest=true;
					}
				}
				if (isBest) {
					bestban = hit.ban;
					besteval = hit.eval;
					bestcnt = hit.cnt;
					descript = hit.descript;
					bestgood = hit.good;
					bestid = hit.getId();
					beststr = hit.getStr(bestid);
				}
			}

			double t = (double) bestcnt / (double) grpSize;
			int score = (int) (t * 100.0);
			// score is tinyint +/- 127
			if (score > 100) score = 100; // shouldn't happen
			String sqlCP = "update pog_groups set " +
							"HITid = "		+ bestid 		+ "," +
							"HITstr = " 		+ quote(beststr) 	+ "," +
							"e_value = " 	+ besteval 		+ "," +
							"score = " 		+ score 			+ " " +
							"where PGid = " + PGid;	
	
			mDB.executeUpdate(sqlCP);	
			cntHits++;
		}
		catch (Exception e) {ErrorReport.die(e, "compute Best Hit");}   
	}
	private class Hits {
		public Hits(int UTid, int HITid, String is, String des, int b, double e, boolean g) {
			member.add(UTid);
			idcnt.put(HITid, 1);
			idstr.put(HITid, is);
			descript = des;
			cnt = 1;
			ban = b;
			eval = e;
			good = g;
		}
		public void add (int UTid, int HITid, String is, int b, double e) {
			int s = 1 + (b*5);
			if (idcnt.containsKey(HITid)) 
				idcnt.put(HITid, idcnt.get(HITid)+s);
			else {
				idcnt.put(HITid, s);
				idstr.put(HITid, is);
			}
			if (!member.contains(UTid)) { // member can have the same descript multiple times, count once
				cnt++;
				if (b==1) ban++;
				member.add(UTid);
			}
			if (e < eval) eval=e;
		}
		public int getId() {
			int bestid=0, bestcnt=0;
			for (int id : idcnt.keySet()) {	
				int c = idcnt.get(id);
				if (c > bestcnt) {
					bestcnt = c;
					bestid = id;
				}
			}
			return bestid;
		}
		public String getStr (int id) { return idstr.get(id);}
		
		public void print (String msg) {
			System.out.println(msg + " " +  cnt + " " + ban + " " + good + " " +  descript);
		}

		HashMap <Integer, Integer> idcnt = new HashMap <Integer, Integer> ();
		HashMap <Integer, String> idstr = new HashMap <Integer, String> ();
		Vector <Integer> member = new Vector <Integer> ();
		public String descript;
		public int cnt, ban;
		public Double eval;
		public boolean good;
	}
	
	/*****************************************************
	 *   For each cluster, add the RPKM >=1000 and PCC>=0.8 columns 
	 */
	private void step4_updateClusterCnts(int PMid)
	{
		CompileMain.PrtSpMsg(2, "Add cluster counts for RPKM and DE");
		long ts = CompileMain.getTime();
		ResultSet rs;
		int [] csize = new int [6];
		for (int i=0; i<6; i++) csize[i]=0;
		
		try
		{
			DBinfo info = new DBinfo(mDB, true);
			String [] seqDE = info.getSeqDE();
			String [] seqLib = info.getSeqLib();
			CompileMain.PrtSpMsg(3, "Lib: " + seqLib.length + " DE: " + seqDE.length);
			
	// get list of clusters from this method
			int nPOG = mDB.executeCount("select count(*) from pog_groups where PMid=" + PMid);
			CompileMain.PrtSpMsg(3, "Number of Clusters to process " + nPOG);	
			int [] PGid = new int [nPOG+1]; 
			rs = mDB.executeQuery("select PGid from pog_groups where PMid=" + PMid);
			int x=0;
			while (rs.next()) PGid[x++] = rs.getInt(1);
						
	/** for each cluster **/
			for (int c=0; c< nPOG; c++) {
				// get the members
				Vector <Integer> members = new Vector <Integer> ();
				rs= mDB.executeQuery("select UTid from pog_members where PGid=" + PGid[c]);
				while (rs.next()) members.add(rs.getInt(1));
				int nMem = members.size();
				System.err.print("   Computed counts for cluster #" + PGid[c] + " size " + nMem + "\r");
				if (nMem < 5) csize[0]++;
				else if (nMem <=15) csize[1]++;
				else if (nMem <=50) csize[2]++;
				else if (nMem <= 75) csize[3]++;
				else if (nMem <= 100) csize[4]++;
				else csize[5]++;
				
				HashMap <String, Double[]> libVal = new HashMap <String, Double []> ();
				HashMap <String, Double[]> deVal = new HashMap <String, Double[]> ();
				double [] rsVal = new double [seqLib.length+seqDE.length];
				int nrs = seqLib.length+seqDE.length;
				
			/** get all values for this cluster **/
				for (int midx=0; midx< nMem; midx++) {
					String qstr = "Select " + info.getSeqLibSQL();
					String destr = info.getSeqDESQL();
					if (!destr.equals(""))
					{
						qstr += "," + destr;
					}
					qstr += " from unitrans where UTid=" + members.get(midx);
					rs = mDB.executeQuery(qstr);		
					if (!rs.next()) ErrorReport.die("Error reading for Lib and DE values");
					for (int i=0; i<nrs; i++) rsVal[i] = rs.getDouble(i+1); 
					rs.close();
					
					// get lib values
					int loc=0;
					for (int k=0; k<seqLib.length; k++) {					
						String lib = seqLib[k];
						Double [] val;				
						if (libVal.containsKey(lib)) val = libVal.get(lib);
						else val = new Double [nMem];
						
						val[midx] = rsVal[loc++];
						libVal.put(lib, val);
					}
					// get DE values
					for (int k=0; k<seqDE.length; k++) {
						String de = seqDE[k];
						Double [] val;
						if (deVal.containsKey(de)) val = deVal.get(de);
						else val = new Double [nMem];
						
						val[midx] = rsVal[loc++];
						deVal.put(de, val);
					}
				}
		/** compute counts for this cluster 
		 	values of -1 mean the dataset does not have a value
		 	should these not be included in the overall count?
		 	**/
				String sqlCol = null;
				boolean update=false;
				// library RPKM
				for (int k=0; k<seqLib.length; k++) { // for each library
			
						Double [] vals = libVal.get(seqLib[k]);
						if (vals==null) continue; // no values for this lib for this cluster
						int vcnt = 0, totcnt = 0;
						for (int i=0; i< vals.length; i++) {
							if (vals[i]> -1) {
								totcnt++;
								if (vals[i]>= Globals.RPKMcutoff) vcnt++;
							}
						}
						if (totcnt>0) {
							update = true;
							double perc = ((double) vcnt/totcnt) * 100.0;
						
							if (sqlCol==null) sqlCol = Globals.PRE_LIBCNT + seqLib[k] + "=" + Globals.saveDouble(perc);
							else sqlCol += "," + Globals.PRE_LIBCNT + seqLib[k] + "=" + Globals.saveDouble(perc);
						}
				}
				// DE
				for (int k=0; k<seqDE.length; k++) {
					Double [] vals = deVal.get(seqDE[k]);
					if (vals==null) continue;
					
					int vcnt=0, totcnt=0;
					for (int i=0; i<vals.length; i++) {
						if (vals[i] > -1) {
							totcnt++;
							if (Math.abs(vals[i]) < Globals.DEcutoff) vcnt++;
						}					
					}
					if (totcnt!=0) {
						update = true;
						double perc = ((double) vcnt/totcnt) * 100.0;
;
						if (sqlCol==null) sqlCol = Globals.PRE_DECNT + seqDE[k] + "=" + Globals.saveDouble(perc);
						else sqlCol += "," + Globals.PRE_DECNT + seqDE[k] + "=" + Globals.saveDouble(perc);
					}
				}
				// enter values for this cluster
				if (update) mDB.executeUpdate("Update pog_groups set " + sqlCol + " where PGid=" + PGid[c]);	
			} // end loop  through clusters
			rs.close();
			String msg = String.format("%8s %8s %8s %8s %8s", "<=5", "<=15", "<=25", "<=75", "<=100", ">100");
			CompileMain.PrtSpMsg(3, "Cluster sizes");
			CompileMain.PrtSpMsg(3, msg);
			msg = String.format("%8s %8s %8s %8s %8s", csize[0], csize[1],csize[2],csize[3],csize[4],csize[5]); 
			CompileMain.PrtSpMsg(3, msg);
			CompileMain.PrtSpMsgTime(2, "Finish cluster counts                                  ", ts);
		}
		catch(Exception e)
		{
			ErrorReport.die(e, "Error updating cluster counts.");
		}
	}	

	private void step5_updateGroupGOs(int PMid) 
	{
		try
		{
			boolean haveGODB = CompileMain.checkGODB() && mDB.hasTable("unitrans_go") && mDB.hasTable("pog_go");
			if (!haveGODB) return;
			CompileMain.PrtSpMsg(2, "Add GOs to new groups");
			mDB.executeUpdate("insert ignore into pog_go select pm.PGid, ug.UTid, ug.gonum, ug.bestHit, ug.bestScore " +
					" from pog_groups as pg join pog_members as pm on pm.PGid=pg.PGid " +
					" join unitrans_go as ug on ug.UTid=pm.UTid " +
					" order by pm.PGid asc, ug.gonum asc, ug.bestScore asc ");
		}
		catch(Exception e)
		{
			ErrorReport.prtReport(e, "Error updating group GOs.");			
		}
	}
	 private String quote(String word) {
		return "'" + word + "'"; 
	}

	 private int cntHits=0, cntSeqs=0, nAsm=0;
		
	 private int PMid;
	 private DBConn mDB;
	 private CompilePanel cmpPanel;
	
	 private String prefix;
	 private String groupFile;
	 
	 private Pattern grpPat = Pattern.compile("(\\w+)\\|(\\w+)"); 
	 private HashMap <String, Integer> 	utMap = new HashMap <String, Integer> ();
	 private Vector <String> 			specVec = new Vector <String> ();
	 private HashMap <String, Integer> 	prefMap = new HashMap <String, Integer> ();
}
